<!--
 * @Description:
 * @Version: 1.0
 * @Author: liguansheng
 * @Date: 2022-08-25 15:31:59
 * @LastEditors: liguansheng
 * @LastEditTime: 2022-08-30 13:56:00
-->
<template>
  <Dialog
    :title="props.editId ? '修改' : '新增'"
    @handle-confirm="handleConfirm"
    @closed="handleDialogClosed"
    @open="handleDialogOpen"
    :confirm-disabled="!(clientInfo.clientId && clientInfo.clientName)"
  >
    <AppTabs
      type="card"
      :tabs="tabsSetting"
      v-model:active-tab-id="activeTabId"
    >
      <!-- 详情 -->
      <template #clientInfo>
        <clientInfoForm
          :type="props.editId ? 'edit' : 'add'"
          v-model="clientInfo"
        />
      </template>
      <!-- uris -->
      <template #urisForm>
        <urisForm v-model="urisFormData" />
      </template>
      <!-- Secrets -->
      <template #setSecretsForm>
        <setSecretsForm v-model:secrets="secrets" />
      </template>
      <!-- Identity资源 -->
      <template #setIdentityResourceForm>
        <setIdentityResourceForm
          :data="allIdentityResources"
          v-model:activate="identityResources"
        />
      </template>
      <!-- Api资源 -->
      <template #setApiResourceForm>
        <setApiResourceForm
          :data="allApiResources"
          v-model:activate="apiResources"
        />
      </template>
      <!-- Callback -->
      <template #setCallback>
        <setUrlsForm v-model:urls="callbackUrls" />
      </template>
      <!-- Signout -->
      <template #setSignOut>
        <setUrlsForm v-model:urls="signOutUrls" />
      </template>
      <!-- cors -->
      <template #setCORS>
        <setUrlsForm v-model:urls="corsUrls" />
      </template>
      <template #tokenForm>
        <tokenForm v-model="tokenFormData" />
      </template>
      <template #clientClaimForm>
        <clientClaimForm
          v-model:claims="clientClaimFormData"
          v-model:always-send-client-claims="alwaysSendClientClaims"
        />
      </template>
      <template #clientGrantTypeForm>
        <clientGrantTypeForm v-model:grant-type="grantTypeFormData" />
      </template>
      <template #clientRestrictionsFrom>
        <clientRestrictionsFrom
          v-model:restrictions="restrictionsData"
          v-model:enable-local-login="enableLocalLogin"
        />
      </template>
      <!-- 属性 -->
      <template #setPropertiesForm>
        <setPropertiesForm v-model:properties="properties" />
      </template>
    </AppTabs>
  </Dialog>
</template>

<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { computed, ref, watch } from 'vue'

import AppTabs from '@/components/AppTabs/index.vue'
import { ITabsConfig } from '@/components/AppTabs/type'
import Dialog from '@/components/Dialog/index.vue'
import { getAllApiResources } from '@/http/apiResources'
import { createClient, getClient, updateClient } from '@/http/client'
import { getAllIdentityResources } from '@/http/identityResources'
import { IClientClaim, IUpdateClient } from '@/http/types/client'
import setPropertiesForm from '@/views/system/identityServer/components/setPropertiesForm.vue'
import setSecretsForm from '@/views/system/identityServer/components/setSecretsForm.vue'

import setApiResourceForm from '../components/setApiResourceForm.vue'
import setIdentityResourceForm from '../components/setIdentityResourceForm.vue'
import setUrlsForm from '../components/setUrlsForm.vue'
import { IProperty, ISecret } from '../components/types'
import clientClaimForm from './clientClaimForm.vue'
import clientGrantTypeForm from './clientGrantTypeForm.vue'
import clientInfoForm from './clientInfoForm.vue'
import clientRestrictionsFrom from './clientRestrictionsFrom.vue'
import tokenForm from './tokenForm.vue'
import urisForm from './urisForm.vue'

const props = defineProps({
  editId: {
    type: String,
    default: '',
  },
})
interface EmitsType {
  (e: 'update:editId', value: number | string): void
  (e: 'success'): void
}
const emit = defineEmits<EmitsType>()

const activeTabId = ref('clientInfo')
const tabsSetting = computed<ITabsConfig[]>(() => {
  let setting = [
    {
      name: '信息',
      id: 'clientInfo',
    },
    {
      name: 'Uris',
      id: 'urisForm',
    },
    {
      name: 'Secrets',
      id: 'setSecretsForm',
    },
    {
      name: '资源',
      id: 'resource',
      children: [
        {
          name: 'Identity资源',
          id: 'setIdentityResourceForm',
        },
        {
          name: 'Api资源',
          id: 'setApiResourceForm',
        },
      ],
    },
  ]
  if (props.editId) {
    setting = [
      {
        name: '详情',
        id: 'clientInfo',
      },
      {
        name: '应用程序Urls',
        id: 'uris',
        children: [
          {
            name: 'Callback',
            id: 'setCallback',
          },
          {
            name: 'Signout',
            id: 'setSignOut',
          },
          {
            name: 'CORS',
            id: 'setCORS',
          },
        ],
      },
      {
        name: 'Secrets',
        id: 'setSecretsForm',
      },
      {
        name: '资源',
        id: 'resource',
        children: [
          {
            name: 'Identity资源',
            id: 'setIdentityResourceForm',
          },
          {
            name: 'Api资源',
            id: 'setApiResourceForm',
          },
        ],
      },
      {
        name: 'Advanced',
        id: 'Advanced',
        children: [
          {
            name: '令牌',
            id: 'tokenForm',
          },
          {
            name: '声明',
            id: 'clientClaimForm',
          },
          {
            name: '授予类型',
            id: 'clientGrantTypeForm',
          },
          {
            name: 'Restrictions',
            id: 'clientRestrictionsFrom',
          },
          {
            name: '属性',
            id: 'setPropertiesForm',
          },
        ],
      },
    ]
  }
  return setting
})

const clientInfo = ref({
  clientId: '',
  clientName: '',
  description: '',
  clientUri: '',
  logoUri: '',
  requireConsent: false,
  requireRequestObject: false,
  allowRememberConsent: false,
  enabled: false,
  allowOfflineAccess: false,
  frontChannelLogoutUri: '',
  frontChannelLogoutSessionRequired: false,
  backChannelLogoutUri: '',
  backChannelLogoutSessionRequired: false,
  allowedIdentityTokenSigningAlgorithms: '',
})
const urisFormData = ref({
  callbackUrl: '',
  logoutUrl: '',
})
const secrets = ref<ISecret[]>([])
const identityResources = ref<string[]>([])
const apiResources = ref<string[]>([])
watch(identityResources, (newValue) => {
  console.log('identityResources')
  console.log(newValue)
})
watch(apiResources, (newValue) => {
  console.log('apiResources')
  console.log(newValue)
})
const callbackUrls = ref<string[]>([])
const signOutUrls = ref<string[]>([])
const corsUrls = ref<string[]>([])
const properties = ref<IProperty[]>([])
const tokenFormData = ref({
  accessTokenLifeTime: 0,
  accessTokenType: 0,
  consentLifetime: 0,
  pairWiseSubjectSalt: '',
  includeJwtId: false,
  userSsoLifetime: 0,
  userCodeType: '',
  deviceCodeLifetime: 0,
  requirePkce: false,
  requireClientSecret: false,
  allowAccessTokensViaBrowser: false,
})
const clientClaimFormData = ref<IClientClaim[]>([])
const alwaysSendClientClaims = ref(false)
const grantTypeFormData = ref<string[]>([])
const restrictionsData = ref<string[]>([])
const enableLocalLogin = ref(false)

const handleConfirm = async () => {
  if (props.editId) {
    const data: IUpdateClient = {
      accessTokenLifeTime: tokenFormData.value.accessTokenLifeTime,
      accessTokenType: tokenFormData.value.accessTokenType,
      allowAccessTokensViaBrowser:
        tokenFormData.value.allowAccessTokensViaBrowser,
      allowOfflineAccess: clientInfo.value.allowOfflineAccess,
      allowRememberConsent: clientInfo.value.allowRememberConsent,
      allowedCorsOrigins: corsUrls.value,
      allowedGrantTypes: grantTypeFormData.value,
      allowedIdentityTokenSigningAlgorithms:
        clientInfo.value.allowedIdentityTokenSigningAlgorithms,
      alwaysSendClientClaims: alwaysSendClientClaims.value,
      backChannelLogoutSessionRequired:
        clientInfo.value.backChannelLogoutSessionRequired,
      backChannelLogoutUri: clientInfo.value.backChannelLogoutUri,
      claims: clientClaimFormData.value,
      clientName: clientInfo.value.clientName,
      clientUri: clientInfo.value.clientUri,
      consentLifetime: tokenFormData.value.consentLifetime,
      description: clientInfo.value.description,
      deviceCodeLifetime: tokenFormData.value.deviceCodeLifetime,
      enableLocalLogin: enableLocalLogin.value,
      enabled: clientInfo.value.enabled,
      frontChannelLogoutSessionRequired:
        clientInfo.value.frontChannelLogoutSessionRequired,
      frontChannelLogoutUri: clientInfo.value.frontChannelLogoutUri,
      identityProviderRestrictions: restrictionsData.value,
      includeJwtId: tokenFormData.value.includeJwtId,
      logoUri: clientInfo.value.logoUri,
      pairWiseSubjectSalt: tokenFormData.value.pairWiseSubjectSalt,
      postLogoutRedirectUris: signOutUrls.value,
      properties: properties.value.map((item) => {
        return {
          key: item.key,
          value: item.value,
        }
      }),
      redirectUris: callbackUrls.value,
      requireClientSecret: tokenFormData.value.requireClientSecret,
      requireConsent: clientInfo.value.requireConsent,
      requirePkce: tokenFormData.value.requirePkce,
      requireRequestObject: clientInfo.value.requireRequestObject,
      scopes: Array.from(
        new Set(identityResources.value.concat(apiResources.value)),
      ),
      userCodeType: tokenFormData.value.userCodeType,
      userSsoLifetime: tokenFormData.value.userSsoLifetime,
      clientSecrets: secrets.value.map((item) => {
        return {
          type: item.type,
          value: item.value,
          description: item.description,
          expiration: item.expiration,
        }
      }),
    }
    await updateClient(props.editId, data)
  } else {
    const data = {
      clientId: clientInfo.value.clientId,
      clientName: clientInfo.value.clientName,
      description: clientInfo.value.description,
      clientUri: clientInfo.value.clientUri,
      logoUri: clientInfo.value.logoUri,
      requireConsent: clientInfo.value.requireConsent,
      callbackUrl: urisFormData.value.callbackUrl,
      logoutUrl: urisFormData.value.logoutUrl,
      scopes: identityResources.value.concat(apiResources.value),
      secrets: secrets.value,
    }
    await createClient(data)
  }
  ElMessage.success('保存成功')
  emit('success')
}

const handleDialogClosed = () => {
  activeTabId.value = 'clientInfo'
  emit('update:editId', '')
}
const handleDialogOpen = async () => {
  clientInfo.value = {
    clientId: '',
    clientName: '',
    description: '',
    clientUri: '',
    logoUri: '',
    requireConsent: false,
    requireRequestObject: false,
    allowRememberConsent: false,
    enabled: false,
    allowOfflineAccess: false,
    frontChannelLogoutUri: '',
    frontChannelLogoutSessionRequired: false,
    backChannelLogoutUri: '',
    backChannelLogoutSessionRequired: false,
    allowedIdentityTokenSigningAlgorithms: '',
  }
  urisFormData.value = {
    callbackUrl: '',
    logoutUrl: '',
  }
  secrets.value = []
  identityResources.value = []
  apiResources.value = []
  callbackUrls.value = []
  signOutUrls.value = []
  corsUrls.value = []
  properties.value = []
  tokenFormData.value = {
    accessTokenLifeTime: 0,
    accessTokenType: 0,
    consentLifetime: 0,
    pairWiseSubjectSalt: '',
    includeJwtId: false,
    userSsoLifetime: 0,
    userCodeType: '',
    deviceCodeLifetime: 0,
    requirePkce: false,
    requireClientSecret: false,
    allowAccessTokensViaBrowser: false,
  }
  clientClaimFormData.value = []
  alwaysSendClientClaims.value = false
  grantTypeFormData.value = []
  restrictionsData.value = []
  enableLocalLogin.value = false
  if (props.editId) {
    await Promise.all([getAllIdentityResourceList(), getAllApiResourceList()])
    initData()
  }
}
const allIdentityResources = ref<
  {
    key: string
    label: string
    disabled: boolean
  }[]
>([])
const getAllIdentityResourceList = async () => {
  const res = await getAllIdentityResources()
  allIdentityResources.value = res.map((item) => {
    return {
      key: item.name,
      label: item.displayName,
      disabled: false,
    }
  })
}
const allApiResources = ref<
  {
    key: string
    label: string
    disabled: boolean
  }[]
>([])
const getAllApiResourceList = async () => {
  const res = await getAllApiResources()
  allApiResources.value = res.map((item) => {
    return {
      key: item.name,
      label: item.displayName,
      disabled: false,
    }
  })
}
const initData = async () => {
  const res = await getClient(props.editId)
  clientInfo.value = {
    clientId: res.clientId,
    clientName: res.clientName,
    description: res.description,
    clientUri: res.clientUri,
    logoUri: res.logoUri,
    requireConsent: res.requireConsent,
    requireRequestObject: res.requireRequestObject,
    allowRememberConsent: res.allowRememberConsent,
    enabled: res.enabled,
    allowOfflineAccess: res.allowOfflineAccess,
    frontChannelLogoutUri: res.frontChannelLogoutUri,
    frontChannelLogoutSessionRequired: res.frontChannelLogoutSessionRequired,
    backChannelLogoutUri: res.backChannelLogoutUri,
    backChannelLogoutSessionRequired: res.backChannelLogoutSessionRequired,
    allowedIdentityTokenSigningAlgorithms:
      res.allowedIdentityTokenSigningAlgorithms,
  }
  secrets.value = res.clientSecrets
  identityResources.value = allIdentityResources.value
    .filter((item) =>
      res.allowedScopes.find((allowedScope) => allowedScope.scope === item.key),
    )
    .map((e) => e.key)
  console.log(identityResources.value)
  apiResources.value = allApiResources.value
    .filter((item) =>
      res.allowedScopes.find((allowedScope) => allowedScope.scope === item.key),
    )
    .map((e) => e.key)
  console.log(apiResources.value)

  callbackUrls.value = res.redirectUris.map((item) => item.redirectUri)
  signOutUrls.value = res.postLogoutRedirectUris.map(
    (item) => item.postLogoutRedirectUri,
  )
  corsUrls.value = res.allowedCorsOrigins.map((item) => item.origin)
  tokenFormData.value = {
    accessTokenLifeTime: res.accessTokenLifetime,
    accessTokenType: res.accessTokenType,
    consentLifetime: res.consentLifetime,
    pairWiseSubjectSalt: res.pairWiseSubjectSalt,
    includeJwtId: res.includeJwtId,
    userSsoLifetime: res.userSsoLifetime,
    userCodeType: res.userCodeType,
    deviceCodeLifetime: res.deviceCodeLifetime,
    requirePkce: res.requirePkce,
    requireClientSecret: res.requireClientSecret,
    allowAccessTokensViaBrowser: res.allowAccessTokensViaBrowser,
  }
  clientClaimFormData.value = res.claims
  alwaysSendClientClaims.value = res.alwaysSendClientClaims
  grantTypeFormData.value = res.allowedGrantTypes.map((item) => item.grantType)
  restrictionsData.value = res.identityProviderRestrictions.map(
    (item) => item.provider,
  )
  enableLocalLogin.value = res.enableLocalLogin
  properties.value = res.properties.map((item) => {
    return {
      key: item.key,
      value: item.value,
    }
  })
}
</script>

<style scoped lang="scss"></style>
